<?php
class aliPaynotify {
    var $gateway;           //网关地址
    var $_key;			  	    //安全校验码
    var $partner;           //合作伙伴ID
    var $sign_type;         //签名方式 系统默认
    var $mysign;            //签名结果
    var $_input_charset;    //字符编码格式
    var $transport;         //访问模式

    /**构造函数
    *从配置文件中初始化变量
    *$partner 合作身份者ID
    *$key 安全校验码
    *$sign_type 签名类型
    *$_input_charset 字符编码格式
    *$transport 访问模式
     */
    function __construct($partner,$key,$sign_type,$_input_charset = "GBK",$transport= "https") {

        $this->transport = $transport;
        if($this->transport == "https") {
            $this->gateway = "https://www.alipay.com/cooperate/gateway.do?";
        }else {
            $this->gateway = "http://notify.alipay.com/trade/notify_query.do?";
        }
        $this->partner          = $partner;
        $this->_key             = $key;
        $this->mysign           = "";
        $this->sign_type	      = $sign_type;
        $this->_input_charset   = $_input_charset;
    }

    /********************************************************************************/

    /**对notify_url的认证
	*返回的验证结果：true/false
     */
    function notify_verify() {
        if($this->transport == "https") {
            $veryfy_url = $this->gateway. "service=notify_verify" ."&partner=" .$this->partner. "&notify_id=".$_POST["notify_id"];
        } else {
            $veryfy_url = $this->gateway. "partner=".$this->partner."&notify_id=".$_POST["notify_id"];
        }
        $veryfy_result = $this->get_verify($veryfy_url);
        if(empty($_POST)) {
          return false;
        }
        else {		
          $post          = $this->para_filter($_POST);	    //对所有POST返回的参数去空
          $sort_post     = $this->arg_sort($post);	    //对所有POST反馈回来的数据排序
          $mysign  = $this->build_mysign($sort_post,$this->_key,$this->sign_type);   //生成签名结果
              if (preg_match("/true$/i",$veryfy_result) && $mysign == $_POST["sign"]) {
                return true;
              } else {
                return false;
              }
        }
    }
    /**对return_url的认证
	*return 验证结果：true/false
     */
    function return_verify() {
        if($this->transport == "https") {
            $veryfy_url = $this->gateway. "service=notify_verify" ."&partner=" .$this->partner. "&notify_id=".$_GET["notify_id"];
        } else {
            $veryfy_url = $this->gateway. "partner=".$this->partner."&notify_id=".$_GET["notify_id"];
        }
        $veryfy_result = $this->get_verify($veryfy_url);
        if(empty($_GET)) {
          return false;
        }
        else {
          $get           = $this->para_filter($_GET);	    //对所有GET反馈回来的数据去空
          $sort_get      = $this->arg_sort($get);		    //对所有GET反馈回来的数据排序
          $mysign  = $this->build_mysign($sort_get,$this->_key,$this->sign_type);    //生成签名结果
              if (preg_match("/true$/i",$veryfy_result) && $mysign == $_GET["sign"]) {            
                return true;
              }else {
                return false;
              }
        }
    }

    /********************************************************************************/

    /**获取远程服务器ATN结果
	*$url 指定URL路径地址
	*return 服务器ATN结果集
     */
    function get_verify($url,$time_out = "60") {
        $urlarr     = parse_url($url);
        $errno      = "";
        $errstr     = "";
        $transports = "";
        if($urlarr["scheme"] == "https") {
            $transports = "ssl://";
            $urlarr["port"] = "443";
        } else {
            $transports = "tcp://";
            $urlarr["port"] = "80";
        }
        $fp=@fsockopen($transports . $urlarr['host'],$urlarr['port'],$errno,$errstr,$time_out);
        if(!$fp) {
            die("ERROR: $errno - $errstr<br />\n");
        } else {
            fputs($fp, "POST ".$urlarr["path"]." HTTP/1.1\r\n");
            fputs($fp, "Host: ".$urlarr["host"]."\r\n");
            fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
            fputs($fp, "Content-length: ".strlen($urlarr["query"])."\r\n");
            fputs($fp, "Connection: close\r\n\r\n");
            fputs($fp, $urlarr["query"] . "\r\n\r\n");
            while(!feof($fp)) {
                $info[]=@fgets($fp, 1024);
            }
            fclose($fp);
            $info = implode(",",$info);
            return $info;
        }
    }

    /********************************************************************************/
    function build_mysign($sort_array,$key,$sign_type = "MD5") {
        $prestr = $this->create_linkstring($sort_array);     	//把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        $prestr = $prestr.$key;							//把拼接后的字符串再与安全校验码直接连接起来
        $mysgin = $this->sign($prestr,$sign_type);			    //把最终的字符串签名，获得签名结果
        return $mysgin;
    }	

    /********************************************************************************/

    /**把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
      *$array 需要拼接的数组
      *return 拼接完成以后的字符串
    */
    function create_linkstring($array) {
        $arg  = "";
        while (list ($key, $val) = each ($array)) {
            $arg.=$key."=".$val."&";
        }
        $arg = substr($arg,0,count($arg)-2);		     //去掉最后一个&字符
        return $arg;
    }

    /********************************************************************************/

    /**除去数组中的空值和签名参数
      *$parameter 签名参数组
      *return 去掉空值与签名参数后的新签名参数组
     */
    function para_filter($parameter) {
        $para = array();
        while (list ($key, $val) = each ($parameter)) {
            if($key == "sign" || $key == "sign_type" || $val == "")continue;
            else	$para[$key] = $parameter[$key];
        }
        return $para;
    }

    /********************************************************************************/

    /**对数组排序
      *$array 排序前的数组
      *return 排序后的数组
     */
    function arg_sort($array) {
        ksort($array);
        reset($array);
        return $array;
    }

    /********************************************************************************/

    /**签名字符串
      *$prestr 需要签名的字符串
      *return 签名结果
     */
    function sign($prestr,$sign_type) {
        $sign='';
        if($sign_type == 'MD5') {
            $sign = md5($prestr);
        }elseif($sign_type =='DSA') {
            //DSA 签名方法待后续开发
            die("DSA 签名方法待后续开发，请先使用MD5签名方式");
        }else {
            die("支付宝暂不支持".$sign_type."类型的签名方式");
        }
        return $sign;
    }
}

